package com.jonas.jgraph.graph;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PointF;
import android.graphics.RectF;
import android.support.annotation.ColorInt;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.LinearInterpolator;

import com.jonas.jgraph.BuildConfig;
import com.jonas.jgraph.R;
import com.jonas.jgraph.inter.BaseGraph;
import com.jonas.jgraph.models.Jchart;
import com.jonas.jgraph.utils.CalloutHelper;
import com.jonas.jgraph.utils.DrawHelper;
import com.jonas.jgraph.utils.MathHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yun.
 * @date 2016/6/8
 * @des [一句话描述]
 * @since [https://github.com/ZuYun]
 * <p><a href="https://github.com/ZuYun">github</a>
 */
public class JcoolGraph extends BaseGraph {
    private static final String TAG = JcoolGraph.class.getSimpleName();

    private Paint mBarPaint;  //柱形图画笔
    private int mBarStanded = 0;  // 以mBarStanded为准 左右散开 ，如果 大于数组 记录数据列表最后一个的index
    private boolean lineStarted;
    private ArrayList<Path> mDashPathList = new ArrayList<>();
    private ArrayList<Path> mLinePathList = new ArrayList<>();

    public Paint getmDashLinePaint() {
        return mDashLinePaint;
    }

    public void setmDashLinePaint(Paint mDashLinePaint) {
        this.mDashLinePaint = mDashLinePaint;
    }

    private Paint mDashLinePaint;  //柱状图的画笔

    private Paint mPointPaint;  //画线上的点的画笔

    public Paint getmPointPaint() {
        return mPointPaint;
    }

    public void setmPointPaint(Paint mPointPaint) {
        this.mPointPaint = mPointPaint;
    }

    private float mLinePointRadio;  //小圆点半径

    public float getmLinePointRadio() {
        return mLinePointRadio;
    }

    /**
     * 小圆点半径
     */
    public void setLinePointRadio(@DimenRes int linePointRadio) {
        mLinePointRadio = linePointRadio;
    }

    public boolean isEmpty = true;  // 处理未传入数据时视图崩溃的情况，全部默认为0，并且防止在横线上出现数据点，由此变量控制

    public boolean isEmpty() {
        return isEmpty;
    }

    public void setEmpty(boolean empty) {
        isEmpty = empty;
    }

    private int mBarShowStyle = StateConstant.BARSHOW_ASWAVE;

    private int mLineMode = StateConstant.LINE_EVERYPOINT;
    private int mShowFromMode = StateConstant.SHOWFROMMIDDLE;
    private int mLineStyle = StateConstant.LINE_CURVE;
    /**
     * linepath动画存储点
     */
    private float[] mCurPosition = new float[2];
    private PathMeasure mPathMeasure;
    private PointF mPrePoint; //Point 用整数标示， PointF 用浮点数表示
    /**
     * 折线两点的间隔
     */
    private float mBetween2Excel;

    public Paint getmShaderAreaPaint() {
        return mShaderAreaPaint;
    }

    public void setmShaderAreaPaint(Paint mShaderAreaPaint) {
        this.mShaderAreaPaint = mShaderAreaPaint;
    }

    /**
     * 线条 和横轴之间的 渐变区域
     */
    private Paint mShaderAreaPaint;  //渐变画笔（阴影）
    private int[] mShaderAreaColors;  //渐变的颜色数组（折线阴影）
    private Path mAniShadeAreaPath = new Path();  // 渐变路径

    private Path mShadeAreaPath = new Path();  // 曲线路径（贝塞尔曲线）

    /**
     * 线条展示的动画风格
     */
    protected int mLineShowStyle = StateConstant.LINESHOW_ASWAVE;

    private Paint mLinePaint;  //画线的paint

    public Paint getmLinePaint() {
        return mLinePaint;
    }

    public void setmLinePaint(Paint mLinePaint) {
        this.mLinePaint = mLinePaint;
    }

    private float mLineWidth = -1;  // 设置默认为2.4px 线的宽度

    /**
     * 渐变色
     */
    private int[] mShaderColors;  // 图表渐变数组

    /**
     * 动画用的变俩
     */
    private float mAniRatio = 1;
    /**
     * 保存的原始路径数据
     */
    private Path mLinePath = new Path();
    private Path mAniLinePath = new Path();

    /**
     * 图表出现动画旋转角度
     */
    private float mAniRotateRatio = 0;

    public JcoolGraph(Context context) {
        this(context, null);
    }

    public JcoolGraph(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public JcoolGraph(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AndroidJgraph); //获取通过layout.xml设置的值
        mLineStyle = a.getInteger(R.styleable.AndroidJgraph_linestyle, StateConstant.LINE_CURVE);
        mLineMode = a.getInteger(R.styleable.AndroidJgraph_linemode, StateConstant.LINE_EVERYPOINT);
        mLineWidth = a.getDimension(R.styleable.AndroidJgraph_linewidth, MathHelper.dip2px(mContext, 1.2f));
        mLineShowStyle = a.getInt(R.styleable.AndroidJgraph_lineshowstyle, StateConstant.LINESHOW_ASWAVE);
        a.recycle();
        initializeData();
    }

    /**
     * 画笔初始化
     */
    @Override
    protected void init(Context context) {
        super.init(context);
        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  // 构建Paint时直接加上去锯齿属性
        mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mShaderAreaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDashLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    /**
     * 画笔设置属性
     */
    private void initializeData() {
        mLineWidth = mLineWidth == -1 ? MathHelper.dip2px(mContext, 1.2f) : mLineWidth;
        //画线条 不设置 style 不会画线
        mLinePaint.setStyle(Paint.Style.STROKE);  ////让画出的图形是空心的
        mDashLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setColor(mNormalColor);      //设置画笔颜色
        mDashLinePaint.setColor(mNormalColor);
        mBarPaint.setColor(mNormalColor);
        mLinePaint.setStrokeWidth(mLineWidth);  //设置画出的线的 粗细程度
        mDashLinePaint.setStrokeWidth(mLineWidth);
    }

    /**
     * 在开始的时候设置着色器
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        paintSetShader(mShaderAreaPaint, mShaderAreaColors);
        paintSetShader(mLinePaint, mShaderColors);
        paintSetShader(mBarPaint, mShaderColors);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();  //如果有save（）和restore（），那么平移、缩放、旋转等操作只对save（）和restore（）作用域之间的代码有效。
        canvas.rotate(  // 旋转角度
                mAniRotateRatio);  //float k = Math.abs((p2.y - p1.y)/(p2.x - p1.x));   //斜率 double mAniRotateRatio  = Math.atan(k); //注意这个角度的范围是0 ----------pi/2, 不是0到90°
        canvas.translate(mSliding, 0);  ////将坐标中心平移到midPoint midPoint.x, midPoint.y
        super.onDraw(canvas);
        canvas.restore();  // 释放save
        //纵轴信息固定
        if (mNeedY_abscissMasg && mYaxis_msg != null) {  // 画纵坐标
            drawYabscissaMsg(canvas,getMJcharts(),getMChartRithtest_x(),getMBarWidth());  //画纵坐标信息和虚线
        }
    }

    /**
     * 画柱状图
     */
    @Override
    protected void drawSugExcel_BAR(Canvas canvas) {
        for (Jchart jchart : mJcharts) {
            canvas.drawRect(jchart.getStandedRectF(), mCoordinatePaint);  // 这个画出来应该是一节一节的线才对
        }
        if (mState == StateConstant.aniChange && mAniRatio < 1) {
            barAniChanging(canvas);
            //            for(Jchart jchart : mJcharts) {
            //                jchart.draw(canvas, mCoordinatePaint, false);
            //            }
        } else {  // 第一次加载数据
            mState = -1;
            if (mLastJchart.getAniratio() >= 1 && !mValueAnimator.isRunning()) {
                for (Jchart jchart : mJcharts) {
                    jchart.draw(canvas, mBarPaint, false);  // 传入 true 表示画点
                }
            } else if (mBarShowStyle == StateConstant.BARSHOW_ASWAVE) {    //正常画
                for (Jchart jchart : mJcharts) {
                    jchart.draw(canvas, mBarPaint, false);
                }
            } else if (mBarShowStyle == StateConstant.BARSHOW_FROMLINE) {  // 顶部慢慢变化到指定位置
                barAniChanging(canvas);
            } else if (mBarShowStyle == StateConstant.BARSHOW_EXPAND) {  //柱形条 由某个往外扩散
                drawBarExpand(canvas);
            } else if (mBarShowStyle == StateConstant.BARSHOW_SECTION) {  //线条 一段一段显示
                drawBarSection(canvas);
            }
        }
    }

    //画图 一个一个画
    private void drawBarSection(Canvas canvas) {
        for (int i = 0; i < ((int) mAniRatio); i++) {
            Jchart jchart = mJcharts.get(i);
            jchart.draw(canvas, mBarPaint, false);
        }
    }

    // 画图 柱形条 由某个往外扩散
    private void drawBarExpand(Canvas canvas) {
        if (mBarStanded >= mJcharts.size()) {
            mBarStanded = mJcharts.size() - 1;
        }
        for (Jchart jchart : mJcharts) {
            Jchart sjchart = mJcharts.get(mBarStanded);
            //以mBarStanded为准 左右散开
            canvas.drawRect(sjchart.getRectF().left + (jchart.getRectF().left - sjchart.getRectF().left) * mAniRatio,
                    jchart.getRectF().top,
                    sjchart.getRectF().right + (jchart.getRectF().right - sjchart.getRectF().right) * mAniRatio,
                    jchart.getRectF().bottom, mBarPaint);
        }
    }

    //画图 线条 一从直线慢慢变成折线/曲线
    private void barAniChanging(Canvas canvas) {
        for (int i = 0; i < mJcharts.size(); i++) {
            Jchart jchart = mJcharts.get(i);  // 得到数据对象
            float lasty = mAllLastPoints.get(i).y;  //
            RectF rectF = jchart.getRectF();
            //            if(jchart.mTopRound) {
            //                Path rectFPath = jchart.getRectFPath(rectF.bottom, lasty+( rectF.top-lasty )*mAniRatio);
            //                canvas.drawPath(rectFPath,mBarPaint);
            //            }else {
            //                RectF drectf = new RectF(rectF.left, lasty+( rectF.top-lasty )*mAniRatio, rectF.right, rectF.bottom);
            //                canvas.drawRect(drectf, mBarPaint);
            //            }
            RectF drectf = new RectF(rectF.left, lasty + (rectF.top - lasty) * mAniRatio, rectF.right, rectF.bottom);
            // ToDo 画矩形
            canvas.drawRect(drectf, mBarPaint);
        }
    }

    /**
     * 画折现图
     */
    @Override
    protected void drawSugExcel_LINE(Canvas canvas) {
        if (mState == StateConstant.aniChange && mAniRatio < 1) {
            drawLineAllFromLine(canvas);
            for (Jchart jchart : mJcharts) {
                jchart.draw(canvas, mLinePaint, true);
            }
            drawLeftShaderArea(canvas);
        } else {
            mState = -1;
            if (mLineMode == StateConstant.LINE_EVERYPOINT) {
                //不跳过为0的点
                lineWithEvetyPoint(canvas);
            } else {
                //跳过为0的点（断开，虚线链接）
                lineSkip0Point(canvas);
            }
            //            }
        }
        //画线上的点
        if (mLinePointRadio > 0) {
            for (Jchart jchart : mJcharts) {
                //if (jchart.getHeight() > 0) {  //由此判断是否画横线上的点
                if (isEmpty) {
                    PointF midPointF = jchart.getMidPointF();
                    //ToDo 画线上的点
                    canvas.drawCircle(midPointF.x, midPointF.y, mLinePointRadio, mPointPaint);
                    //                    mPointPaint.setColor(Color.parseColor("#ffffffff"));
                    mPointPaint.setColor(0Xffffffff);  // 设置画笔颜色
                    mPointPaint.setStrokeWidth(MathHelper.dip2px(mContext, 2));  //设置线宽
                    canvas.drawCircle(midPointF.x, midPointF.y, mLinePointRadio, mPointPaint);
                }

                //}
            }
        }
    }

    /**
     * 为画笔 设置 渲染器
     */
    protected void paintSetShader(Paint paint, int[] shaders) {
        paintSetShader(paint, shaders, mChartArea.left, mChartArea.top, mChartArea.left,
                mChartArea.bottom);  // 设置画笔的着色器
    }

    private void lineWithEvetyPoint(Canvas canvas) {

        if ((mLineShowStyle == StateConstant.LINESHOW_FROMCORNER || mLineShowStyle == StateConstant.LINESHOW_DRAWING ||
                mLineShowStyle == StateConstant.LINESHOW_SECTION) && !mValueAnimator.isRunning()) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "drawSugExcel_LINE animationfinish to the initial state");
            }
            //动画不在执行的时候
            mAniShadeAreaPath.reset();
            mAniLinePath.reset();
            // ToDo  画线
            canvas.drawPath(mLinePath, mLinePaint);
            if (mShaderAreaColors != null) {
                canvas.drawPath(mShadeAreaPath, mShaderAreaPaint);
            }
        } else if (mLineShowStyle == StateConstant.LINESHOW_DRAWING) {
            drawLineAllpointDrawing(canvas);
        } else if (mLineShowStyle == StateConstant.LINESHOW_SECTION) {
            drawLineAllpointSectionMode(canvas);
        } else if (mLineShowStyle == StateConstant.LINESHOW_FROMLINE) {
            drawLineAllFromLine(canvas);
            drawLeftShaderArea(canvas);
        } else if (mLineShowStyle == StateConstant.LINESHOW_FROMCORNER) {
            drawLineAllFromCorner(canvas);
            drawLeftShaderArea(canvas);
        } else if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE) {
            drawLineAsWave(canvas);
            drawLeftShaderArea(canvas);
        }
    }

    private void drawLeftShaderArea(Canvas canvas) {
        //渐变区域
        if (mShaderAreaColors != null) {
            mAniShadeAreaPath.lineTo(mChartRithtest_x, mChartArea.bottom);
            mAniShadeAreaPath.lineTo(mChartLeftest_x, mChartArea.bottom);
            mAniShadeAreaPath.close();
            canvas.drawPath(mAniShadeAreaPath, mShaderAreaPaint);
        }
    }

    private void drawLineAllFromCorner(Canvas canvas) {
        mAniShadeAreaPath.reset();
        mAniLinePath.reset();
        if (mLineStyle == StateConstant.LINE_CURVE) {
            for (int i = 0; i < mAllPoints.size() - 1; i++) {
                PointF midPointF = mAllPoints.get(i);
                PointF endPointF = mAllPoints.get(i + 1);
                if (mAniLinePath.isEmpty()) {
                    mAniLinePath.moveTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                    mAniShadeAreaPath.moveTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                }
                float con_x = (midPointF.x + endPointF.x) / 2;
                mAniLinePath.cubicTo(con_x * mAniRatio, midPointF.y * mAniRatio, con_x * mAniRatio,
                        endPointF.y * mAniRatio,
                        endPointF.x * mAniRatio, endPointF.y * mAniRatio);
                mAniShadeAreaPath
                        .cubicTo(con_x * mAniRatio, midPointF.y * mAniRatio, con_x * mAniRatio, endPointF.y * mAniRatio,
                                endPointF.x * mAniRatio, endPointF.y * mAniRatio);
            }
        } else {
            for (PointF midPointF : mAllPoints) {
                if (mAniLinePath.isEmpty()) {
                    mAniLinePath.moveTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                    mAniShadeAreaPath.moveTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                } else {
                    mAniLinePath.lineTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                    mAniShadeAreaPath.lineTo(midPointF.x * mAniRatio, midPointF.y * mAniRatio);
                }
            }
        }
        canvas.drawPath(mAniLinePath, mLinePaint);
    }

    /**
     *
     * @param canvas
     */
    private void drawLineAllFromLine(Canvas canvas) {
        mAniShadeAreaPath.reset();
        mAniLinePath.reset();
        if (BuildConfig.DEBUG) {
            canvas.drawLine(0, mChartArea.bottom, mWidth, mChartArea.bottom, mLinePaint);  // 画柱形图下的一根线
            canvas.drawLine(0, mChartArea.top, mWidth, mChartArea.top, mLinePaint);  // 画柱形图顶部的一根线
        }
        if (mAllPoints.size() != mJcharts.size()) {
            throw new RuntimeException("mAllPoints.size() == mJcharts.size()");
        }
        if (mLineStyle == StateConstant.LINE_CURVE) {  // 如果为曲线
            for (int i = 0; i < mAllPoints.size() - 1; i++) {
                PointF midPointF = mAllPoints.get(i);
                PointF endPointF = mAllPoints.get(i + 1);
                PointF midLastPointF = mAllLastPoints.get(i);
                PointF endLastPointF = mAllLastPoints.get(i + 1);
                if (mAniLinePath.isEmpty()) {
                    mAniLinePath.moveTo(midPointF.x, midLastPointF.y + (midPointF.y - midLastPointF.y) * mAniRatio);
                    mAniShadeAreaPath.moveTo(midPointF.x,
                            midLastPointF.y + (midPointF.y - midLastPointF.y) * mAniRatio);
                }
                DrawHelper.AnipathCubicFromLast(mAniLinePath, midPointF, endPointF, midLastPointF, endLastPointF,
                        mAniRatio);
                DrawHelper.AnipathCubicFromLast(mAniShadeAreaPath, midPointF, endPointF, midLastPointF, endLastPointF,
                        mAniRatio);
            }
        } else {  // 折线
            for (int i = 0; i < mAllPoints.size(); i++) {
                PointF midPointF = mAllPoints.get(i);
                PointF lastPointF = mAllLastPoints.get(i);
                if (mAniLinePath.isEmpty()) {
                    mAniLinePath.moveTo(midPointF.x, lastPointF.y + (midPointF.y - lastPointF.y) * mAniRatio);
                    mAniShadeAreaPath.moveTo(midPointF.x, lastPointF.y + (midPointF.y - lastPointF.y) * mAniRatio);
                } else {
                    DrawHelper.AnipathLinetoFromLast(mAniLinePath, midPointF, lastPointF, mAniRatio);
                    DrawHelper.AnipathLinetoFromLast(mAniShadeAreaPath, midPointF, lastPointF, mAniRatio);
                }
            }
        }
        canvas.drawPath(mAniLinePath, mLinePaint);
    }

    private void drawLineAsWave(Canvas canvas) {
        mAniShadeAreaPath.reset();
        mAniLinePath.reset();
        if (mLineStyle == StateConstant.LINE_CURVE) {
            setUpCurveLinePath();
        } else {
            setUpBrokenLinePath();
        }
        canvas.drawPath(mAniLinePath, mLinePaint);
    }

    private void setUpCurveLinePath() {
        for (int i = 0; i < mJcharts.size() - 1; i++) {
            PointF startPoint = mJcharts.get(i).getMidPointF();
            PointF endPoint = mJcharts.get(i + 1).getMidPointF();//下一个点
            if (mAniLinePath.isEmpty()) {
                mAniLinePath.moveTo(startPoint.x, startPoint.y);
                mAniShadeAreaPath.moveTo(startPoint.x, startPoint.y);
            }
            DrawHelper.pathCubicTo(mAniLinePath, startPoint, endPoint);
            DrawHelper.pathCubicTo(mAniShadeAreaPath, startPoint, endPoint);
        }
    }

    private void setUpBrokenLinePath() {
        for (Jchart chart : mJcharts) {
            if (mAniLinePath.isEmpty()) {
                mAniLinePath.moveTo(chart.getMidPointF().x, chart.getMidPointF().y);
                mAniShadeAreaPath.moveTo(chart.getMidPointF().x, chart.getMidPointF().y);
            } else {
                mAniLinePath.lineTo(chart.getMidPointF().x, chart.getMidPointF().y);
                mAniShadeAreaPath.lineTo(chart.getMidPointF().x, chart.getMidPointF().y);
            }
        }
    }

    /**
     * 画出完整线条动画
     */
    private void drawLineAllpointDrawing(Canvas canvas) {
        if (mCurPosition == null) {
            return;
        }
        //动画
        if (mAniLinePath.isEmpty() || mCurPosition[0] <= mChartLeftest_x) {
            mPrePoint = mJcharts.get(0).getMidPointF();
            mAniLinePath.moveTo(mPrePoint.x, mPrePoint.y);
            mAniShadeAreaPath.moveTo(mPrePoint.x, mPrePoint.y);
        } else {
            if (mPrePoint == null) {
                mPrePoint = mJcharts.get(0).getMidPointF();
            }
            if (mLineStyle == StateConstant.LINE_CURVE) {
                float con_X = (mPrePoint.x + mCurPosition[0]) / 2;
                mAniLinePath.cubicTo(con_X, mPrePoint.y, con_X, mCurPosition[1], mCurPosition[0], mCurPosition[1]);
                mAniShadeAreaPath.cubicTo(con_X, mPrePoint.y, con_X, mCurPosition[1], mCurPosition[0], mCurPosition[1]);
            } else {
                mAniLinePath.lineTo(mCurPosition[0], mCurPosition[1]);
                mAniShadeAreaPath.lineTo(mCurPosition[0], mCurPosition[1]);
            }
            mPrePoint.x = mCurPosition[0];
            mPrePoint.y = mCurPosition[1];
        }
        canvas.drawPath(mAniLinePath, mLinePaint);
        Jchart jchart = mJcharts.get((int) ((mCurPosition[0] - mChartArea.left) / mBetween2Excel));
        drawAbscissaMsg(canvas, jchart);
    }

    /**
     * 一段一段 画出线条
     */
    private void drawLineAllpointSectionMode(Canvas canvas) {
        int currPosition = (int) mAniRatio;
        if (currPosition == 0) {
            mAniLinePath.reset();
            mAniShadeAreaPath.reset();
        }
        Jchart jchart = mJcharts.get(currPosition);
        if (mLineStyle == StateConstant.LINE_BROKEN) {
            if (currPosition == 0) {
                mAniLinePath.moveTo(jchart.getMidPointF().x, jchart.getMidPointF().y);
            } else {
                mAniLinePath.lineTo(jchart.getMidPointF().x, jchart.getMidPointF().y);
            }
            canvas.drawPath(mAniLinePath, mLinePaint);
        } else {
            PointF currPointf = jchart.getMidPointF();
            if (mPrePoint == null) {
                mPrePoint = mJcharts.get(0).getMidPointF();
            }
            if (currPosition == 0) {
                mAniLinePath.moveTo(mPrePoint.x, mPrePoint.y);
            }
            DrawHelper.pathCubicTo(mAniLinePath, mPrePoint, currPointf);
            mPrePoint = currPointf;
            canvas.drawPath(mAniLinePath, mLinePaint);
        }
        drawAbscissaMsg(canvas, jchart);
        //渐变区域
        if (mShaderAreaColors != null) {
            mAniShadeAreaPath.reset();
            for (int i = 0; i < currPosition + 1; i++) {
                PointF currPoint = mAllPoints.get(i);
                if (i == 0) {
                    mAniShadeAreaPath.moveTo(currPoint.x, currPoint.y);  // 第一个点
                } else {
                    if (mLineStyle == StateConstant.LINE_BROKEN) {
                        mAniShadeAreaPath.lineTo(currPoint.x, currPoint.y);  // 直线移动到第二个点
                    } else {
                        DrawHelper.pathCubicTo(mAniShadeAreaPath, mAllPoints.get(i - 1), currPoint);  // 贝塞尔曲线方式移动到第二个点
                    }
                }
            }
            mAniShadeAreaPath.lineTo(jchart.getMidX(), mChartArea.bottom); // 移动到最后一个点的最下边
            mAniShadeAreaPath.lineTo(mChartLeftest_x, mChartArea.bottom);  // 移动到第一个点的最下边
            mAniShadeAreaPath.close();            // 形成的path的封闭曲线
            canvas.drawPath(mAniShadeAreaPath, mShaderAreaPaint);  //画渐变区域
        }
    }

    /**
     * 跳过0 点
     */
    private void lineSkip0Point(Canvas canvas) {
        arrangeLineDate(canvas);
        if (mLineMode == StateConstant.LINE_DASH_0) {
            //虚线连接
            arrangeDashLineDate(canvas);
            if (mDashPathList.size() > 0) {
                for (Path path : mDashPathList) {
                    mDashLinePaint.setPathEffect(pathDashEffect(new float[] { 8, 5 }));
                    canvas.drawPath(path, mDashLinePaint);
                }
                postInvalidateDelayed(50);
            }
        }
    }

    protected void arrangeDashLineDate(Canvas canvas) {
        mDashPathList.clear();
        for (int i = 0; i < mLinePathList.size(); i++) {
            Path path = mLinePathList.get(i);
            PathMeasure pathMeasure = new PathMeasure(path, false);
            float length = pathMeasure.getLength();
            float[] post = new float[2];
            pathMeasure.getPosTan(0, post, null);
            float[] post_end = new float[2];
            pathMeasure.getPosTan(length, post_end, null);
            if (length > 0.001f) {
                if (mShaderAreaColors != null && mShaderAreaColors.length > 0) {
                    path.lineTo(post_end[0], mChartArea.bottom);
                    path.lineTo(post[0], mChartArea.bottom);//移动到起点
                    path.close();
                    canvas.drawPath(path, mShaderAreaPaint);
                }
            } else {
                post_end[0] = post[0];
                post_end[1] = post[1];
            }
            if (i < mLinePathList.size() - 1) {
                path = new Path();
                //当前直线的最后一个点
                path.moveTo(post_end[0], post_end[1]);
                //下一条直线的起点
                PathMeasure pathMeasuredotted = new PathMeasure(mLinePathList.get(i + 1), false);
                pathMeasuredotted.getPosTan(0, post, null);

                if (mLineStyle == StateConstant.LINE_BROKEN) {
                    path.lineTo(post[0], post[1]);
                } else {
                    DrawHelper.pathCubicTo(path, new PointF(post_end[0], post_end[1]), new PointF(post[0], post[1]));
                }
                mDashPathList.add(path);
            }
        }
    }

    protected boolean arrangeLineDate(Canvas canvas) {
        Path pathline = null;
        mLinePathList.clear();
        for (int i = 0; i < mJcharts.size(); i++) {
            if (!lineStarted) {
                pathline = new Path();
            }
            Jchart excel = null;
            excel = mJcharts.get(i);
            PointF midPointF = excel.getMidPointF();

            if (pathline != null) {
                if (excel.getHeight() > 0) {
                    if (!lineStarted) {
                        pathline.moveTo(midPointF.x, midPointF.y);
                        lineStarted = true;
                    } else {
                        if (mLineStyle == StateConstant.LINE_BROKEN) {
                            if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE) {
                                pathline.lineTo(midPointF.x, midPointF.y);
                            } else {
                                PointF lastP = mAllLastPoints.get(i);
                                DrawHelper.AnipathLinetoFromLast(pathline, midPointF, lastP, mAniRatio);

                            }
                        } else {
                            if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE) {
                                DrawHelper.pathCubicTo(pathline, mPrePoint, midPointF);
                            } else {
                                PointF laste = mAllLastPoints.get(i);
                                PointF lastP = mAllLastPoints.get(i - 1);
                                DrawHelper
                                        .AnipathCubicFromLast(pathline, mPrePoint, midPointF, lastP, laste, mAniRatio);
                            }
                        }
                    }
                } else {
                    //线段 结束
                    if (!pathline.isEmpty()) {
                        PathMeasure pathMeasure = new PathMeasure(pathline, false);
                        if (i > 0 && pathMeasure.getLength() < 0.001f) {
                            //线段 只有一个点的情况
                            pathline.lineTo(mPrePoint.x, mPrePoint.y + 0.001f);
                        }
                        mLinePathList.add(pathline);
                        canvas.drawPath(pathline, mLinePaint);
                    }
                    lineStarted = false;//线段 结束
                }
                //最后一个点 最后的线段只有最后一个点
                if (i == mJcharts.size() - 1 && lineStarted) {
                    PathMeasure pathMeasure = new PathMeasure(pathline, false);
                    if (i > 0 && pathMeasure.getLength() < 0.001f) {
                        pathline.lineTo(midPointF.x, midPointF.y + 0.001f);
                    }
                    mLinePathList.add(pathline);
                    canvas.drawPath(pathline, mLinePaint);
                }
            }
            mPrePoint = midPointF;
        }
        lineStarted = false;
        return false;
    }

    /**
     * 以动画方式 切换数据
     */
    @Override
    public void aniChangeData(List<Jchart> jchartList) {
        if (mWidth <= 0) {
            throw new RuntimeException("after onsizechange");
        }
        mSliding = 0;//切换数据清除 移动距离
        mState = StateConstant.aniChange;  // 更新数据时至为 aniChange
        if (jchartList != null && jchartList.size() == mAllLastPoints.size()) {  // 数据规模没有变
            mAllLastPoints.clear();
            mSelected = -1;  // 选中状态清 0
            mJcharts.clear();
            mJcharts.addAll(jchartList);  // 将数据保持到mJcharts
            for (int i = 0; i < mJcharts.size(); i++) {
                Jchart jchart = mJcharts.get(i);
                jchart.setIndex(i);  // 设置数据位置
                PointF allPoint = mAllPoints.get(i);
                //保存上一次的数据
                mAllLastPoints.add(new PointF(allPoint.x, allPoint.y)); //保存上次数据的point
            }
            findTheBestChart();  //更新最大的数值
            refreshChartArea();    // 更新画图标的区域
            aniShowChar(0, 1, new LinearInterpolator());
        } else {
            throw new RuntimeException("aniChangeData的数据必须和第一次传递cmddata的数据量相同");
        }
    }

    /**
     * 根据每一个chart刷新其他需要的数据
     */
    @Override
    protected void refreshOthersWithEveryChart(int i, Jchart jchart) {

        if (mGraphStyle == StateConstant.LINE) {
            mAllPoints.add(jchart.getMidPointF());
            if (mAllLastPoints.get(i).y == -1) {
                if (mShowFromMode == StateConstant.SHOWFROMBUTTOM) {
                    mAllLastPoints.get(i).y = mChartArea.bottom;//0转为横轴纵坐标
                } else if (mShowFromMode == StateConstant.SHOWFROMTOP) {
                    mAllLastPoints.get(i).y = mChartArea.top;//0转为横轴纵坐标
                } else if (mShowFromMode == StateConstant.SHOWFROMMIDDLE) {
                    mAllLastPoints.get(i).y = (mChartArea.bottom + mChartArea.top) / 2;//0转为横轴纵坐标
                }
            }
        } else {
            if (BuildConfig.DEBUG) {
                Log.e(TAG, "当前图形 是柱状图");
            }
            //continue; //没必要continue
            mAllPoints.add(jchart.getMidPointF());
            if (mAllLastPoints.get(i).y == -1) {
                mAllLastPoints.get(i).y = mChartArea.bottom;//0转为横轴纵坐标
            }
        }
    }

    /**
     * 主要 刷新高度
     */
    protected void refreshExcels() {
        if (mJcharts == null || mJcharts.size() <= 0) {
            if (BuildConfig.DEBUG) {
                Log.e(TAG, "数据为空 ");
            }
            return;
        }
        mAllPoints.clear();
        super.refreshExcels();
        refreshLinepath();
        mChartRithtest_x = mJcharts.get(mJcharts.size() - 1).getMidPointF().x;
        mChartLeftest_x = mJcharts.get(0).getMidPointF().x;
        if (mJcharts.size() > 1) {
            mBetween2Excel = mJcharts.get(1).getMidPointF().x - mJcharts.get(0).getMidPointF().x;
        }
    }

    private void refreshLinepath() {
        //填充 path
        mLinePath.reset();
        mShadeAreaPath.reset();  // 画阴影的路径
        //曲线
        if (mLineStyle == StateConstant.LINE_CURVE) {
            for (int i = 0; i < mAllPoints.size() - 1; i++) {
                PointF startPoint = mAllPoints.get(i);
                PointF endPoint = mAllPoints.get(i + 1);//下一个点
                if (mLinePath.isEmpty()) {
                    mLinePath.moveTo(startPoint.x, startPoint.y);
                    mShadeAreaPath.moveTo(startPoint.x, startPoint.y);
                }
                DrawHelper.pathCubicTo(mLinePath, startPoint, endPoint);
                DrawHelper.pathCubicTo(mShadeAreaPath, startPoint, endPoint);
            }
        } else {
            for (PointF allPoint : mAllPoints) {
                if (mLinePath.isEmpty()) {
                    mLinePath.moveTo(allPoint.x, allPoint.y);
                    mShadeAreaPath.moveTo(allPoint.x, allPoint.y);
                } else {
                    mLinePath.lineTo(allPoint.x, allPoint.y);
                    mShadeAreaPath.lineTo(allPoint.x, allPoint.y);
                }
            }
        }
        mShadeAreaPath.lineTo(mChartRithtest_x, mChartArea.bottom);
        mShadeAreaPath.lineTo(mChartLeftest_x, mChartArea.bottom);
        mShadeAreaPath.close();
    }

    /**
     * 传入数据
     */
    @Override
    public void feedData(@NonNull List<Jchart> jchartList) {
        super.feedData(jchartList);
    }

    /**
     * 传入数据
     */
    public void feedData(float... data) {
        ArrayList<Jchart> jchartList = new ArrayList<>(data.length);
        for (float v : data) {
            Jchart jchart = new Jchart(v, mNormalColor);
            jchartList.add(jchart);
        }
        super.feedData(jchartList);
    }

    /**
     * 刷新现在的数据
     */
    public void aniShow_growing() {
        if (mJcharts.size() <= 0) {
            if (BuildConfig.DEBUG) {
                Log.e(TAG, "数据异常 ");
            }
            return;
        }
        mState = -1;
        if (mGraphStyle == StateConstant.LINE) {
            if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE) {  // 线性波浪效果
                aswaveAniTrigger();
            } else if (mLineMode == StateConstant.LINE_DASH_0 || mLineMode == StateConstant.LINE_JUMP0 ||
                    mLineShowStyle == StateConstant.LINESHOW_FROMLINE
                    || mLineShowStyle == StateConstant.LINESHOW_FROMCORNER) {
                if (mLineMode == StateConstant.LINE_DASH_0 || mLineMode == StateConstant.LINE_JUMP0) {
                    //跳过0的线只有两种动画 ASWAVE FROMLINE
                    mLineShowStyle = StateConstant.LINESHOW_FROMLINE;
                    if (BuildConfig.DEBUG) {
                        Log.d(TAG, "aniShow_growing change showstyle 2 fromline");
                    }
                }
                if (mShowFromMode == StateConstant.SHOWFROMMIDDLE) {
                    aniShowChar(0, 1, new AccelerateInterpolator());
                } else {
                    aniShowChar(0, 1);
                }
            } else if (mLineShowStyle == StateConstant.LINESHOW_SECTION) {
                mAniLinePath.reset();
                mAniShadeAreaPath.reset();
                aniShowChar(0, mJcharts.size() - 1, new LinearInterpolator(), 5000, true);
            } else if (mLineShowStyle == StateConstant.LINESHOW_DRAWING) {
                mAniLinePath.reset();
                mAniShadeAreaPath.reset();
                mPathMeasure = new PathMeasure(mLinePath, false);
                mPathMeasure.getPosTan(0, mCurPosition, null);
                aniShowChar(0, mPathMeasure.getLength(), new LinearInterpolator(), 3000);
            }
        } else {
            if (mJcharts.size() > 0) {
                if (mBarShowStyle == StateConstant.BARSHOW_ASWAVE) {
                    aswaveAniTrigger();
                } else if (mBarShowStyle == StateConstant.BARSHOW_SECTION) {
                    aniShowChar(0, mJcharts.size() - 1, new LinearInterpolator(), (mJcharts.size() - 1) * 300, true);
                } else {
                    aniShowChar(0, 1, new LinearInterpolator());
                }
            }
        }
    }

    /**
     * 线性 水波方式展示  as Wave Ani Trigger(触发)
     */
    private void aswaveAniTrigger() {
        for (Jchart jchart : mJcharts) {
            jchart.setAniratio(0);  // 动画比例清0
        }
        aniShowChar(0, mJcharts.size() - 1, new LinearInterpolator(), (mJcharts.size() - 1) * 250, true);
    }

    /**
     * 值动画更新回调  在此处复写子类方法
     *
     * @param animation 传入的是值动画返回的值  会不停的回掉
     */
    @Override
    protected void onAnimationUpdating(ValueAnimator animation) {
        if (mState == StateConstant.aniChange) {
            floatChangeAni(animation);
        } else if (mGraphStyle == StateConstant.BAR) {  // 如果为柱形图
            if (mBarShowStyle == StateConstant.BARSHOW_ASWAVE
                    || mBarShowStyle == StateConstant.BARSHOW_SECTION) {  // 展示效果为水波和线条的话
                if (animation.getAnimatedValue() instanceof Integer) {  // 且值为int型
                    mAniRatio = (int) animation.getAnimatedValue();  // 得到int值
                    mJcharts.get(((int) mAniRatio)).aniHeight(this, 0, new AccelerateInterpolator());
                }
            } else {
                floatChangeAni(animation);
            }
        } else {  // 折线
            if (mLineMode == StateConstant.LINE_EVERYPOINT) {  //连接每一个点
                if (mLineShowStyle == StateConstant.LINESHOW_FROMLINE             //  统一的动画值
                        || mLineShowStyle == StateConstant.LINESHOW_FROMCORNER) {  //从左上角 放大
                    floatChangeAni(animation);
                } else if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE    // 水波和线条 自己的动画值
                        || mLineShowStyle == StateConstant.LINESHOW_SECTION) {  //一段一段显示
                    intChangeAni(animation);
                } else {
                    if (animation.getAnimatedValue() instanceof Float) {
                        mAniRatio = (float) animation.getAnimatedValue();
                        if (mGraphStyle == StateConstant.LINE) {  // 如果为线
                            if (mLineShowStyle == StateConstant.LINESHOW_DRAWING && mState != StateConstant.aniChange) {
                                //mCurPosition必须要初始化mCurPosition = new float[2];
                                mPathMeasure.getPosTan(mAniRatio, mCurPosition, null);
                            }
                        }
                    }
                }
            } else {
                if (mLineShowStyle == StateConstant.LINESHOW_FROMLINE) {
                    floatChangeAni(animation);
                } else {
                    //波浪
                    intChangeAni(animation);
                }
            }
        }

        postInvalidate();
    }

    /**
     * int 型改变 动画
     */
    private void intChangeAni(ValueAnimator animation) {
        if (animation.getAnimatedValue() instanceof Integer) {
            int curr = (int) animation.getAnimatedValue();
            mJcharts.get(curr).aniHeight(this);
            mAniRatio = curr;
        }
    }

    /**
     * 设置 mAniRatio 的大小 必须是float
     */
    private void floatChangeAni(ValueAnimator animation) {
        if (animation.getAnimatedValue() instanceof Float) {
            mAniRatio = (float) animation.getAnimatedValue();
        }
    }

    /**
     * onDetachedFromWindow 我们销毁View的时候。我们写的这个View不再显示。
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mAniShadeAreaPath = null;
        mLinePath = null;
        mShaderColors = null;
        mPathMeasure = null;
        mCurPosition = null;
        mAllPoints = null;
        mAllLastPoints = null;
        mAniLinePath = null;
    }

    /**
     * 设置间隔宽度
     */
    @Override
    public void setInterval(float interval) {
        super.setInterval(interval);
        refreshChartSetData();
    }

    /**
     * 线条 宽度
     */
    public void setLineWidth(float lineWidth) {
        mLineWidth = lineWidth;
    }

    /**
     * 画选中的 顶部文字和背景
     */
    protected void drawSelectedText(Canvas canvas, Jchart excel) {
        CalloutHelper.drawCalloutActual(canvas, excel, true, mLineWidth, mChartArea.right, mSelectedTextBgPaint,
                mSelectedTextPaint, mScrollAble);
    }

    /**
     * 渐变色
     * 从上到下
     */
    public void setPaintShaderColors(@ColorInt int... colors) {
        mShaderColors = colors;
        if (mWidth > 0) {
            paintSetShader(mLinePaint, mShaderColors);
            paintSetShader(mBarPaint, mShaderColors);
        }
    }

    /**
     * 设置 折线阴影渐变
     */
    public void setShaderAreaColors(@ColorInt int... colors) {
        mShaderAreaColors = colors;
        if (mWidth > 0) {
            paintSetShader(mShaderAreaPaint, mShaderAreaColors);
            postInvalidate();
        }
    }

    public float getAniRatio() {
        return mAniRatio;
    }

    public void setAniRatio(float aniRatio) {
        this.mAniRatio = aniRatio;
    }

    public float getAniRotateRatio() {
        return mAniRotateRatio;
    }

    public void setAniRotateRatio(float aniRotateRatio) {
        mAniRotateRatio = aniRotateRatio;
        invalidate();
    }

    /**
     * onAttachedToWindow 是在第一次onDraw前调用的。
     * 也就是我们写的View在没有绘制出来时调用的，但只会调用一次。
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (BuildConfig.DEBUG) {
            Log.e(TAG, "onAttachedToWindow ");
        }
    }

    /**
     * 设置展示模式
     */
    @Override
    public void setSelectedMode(@StyleAnnotation.SelectedMode int selectedMode) {
        mSelectedMode = selectedMode;
        if (mWidth > 0) {
            refreshChartArea();
        }
    }

    public void setLineStyle(@StyleAnnotation.LineStyle int lineStyle) {
        mLineStyle = lineStyle;
        if (mWidth > 0) {
            refreshLinepath();
        }
    }

    /**
     * 设置-1 没动画
     *
     * @param lineShowStyle one of {@link StyleAnnotation.LineShowStyle}
     */
    public void setLineShowStyle(@StyleAnnotation.LineShowStyle int lineShowStyle) {
        if (mValueAnimator.isRunning()) {
            mValueAnimator.cancel();
            if (mLineShowStyle == StateConstant.LINESHOW_ASWAVE) {
                for (Jchart jchart : mJcharts) {
                    jchart.setAniratio(1);
                }
            }
            mAniRatio = 1;
        }
        mLineShowStyle = lineShowStyle;
    }

    public void setBarShowStyle(@StyleAnnotation.BarShowStyle int barShowStyle) {
        if (mValueAnimator.isRunning()) {
            mValueAnimator.cancel();
            if (mBarShowStyle == StateConstant.BARSHOW_ASWAVE) {
                for (Jchart jchart : mJcharts) {
                    jchart.setAniratio(1);
                }
            }
        }
        mBarShowStyle = barShowStyle;
    }

    /**
     * 设置fromline动画的最初起点
     *
     * @param showFromMode one of {@link StyleAnnotation.ShowFromMode}
     */
    public void setShowFromMode(@StyleAnnotation.ShowFromMode int showFromMode) {
        mShowFromMode = showFromMode;
    }

    public int getLineMode() {
        return mLineMode;
    }

    /**
     * 当linemode为跳过0时 只有两种动画 aswave和fromline
     */
    public void setLineMode(@StyleAnnotation.LineMode int lineMode) {
        mLineMode = lineMode;
        if (mValueAnimator.isRunning()) {
            mValueAnimator.cancel();
        }
    }

    /**
     * 线宽
     */
    public float getLineWidth() {
        return mLineWidth;
    }

    /**
     * 设置柱形图默认的颜色
     */
    @Override
    public void setNormalColor(@ColorInt int normalColor) {
        super.setNormalColor(normalColor);
        mLinePaint.setColor(mNormalColor);  //设置线的默认颜色
    }
}
//可滚动   根据可见个数 计算barwidth
//
//不可滚动
//   1 无视mVisibleNums 所有柱子平均显示
//   2 固定最多个数mVisibleNums 大于等于mExecels的数量
//